承上一篇內容,我們繼續對角色移動進行調整以及新增跳躍功能。
首先,原本的輸入管理器的軸設定讓我們鍵盤玩家的數值變化反應較慢,我們可以透過改變重力來使放開按鍵後數值回0的速度變快,亦可以改變靈敏度去讓按下按鍵後數值由0到1的速度變快。
然後,我們要讓角色可以根據我們輸入的方向去決定面向左還是右,我們可以透過改變人物的 rotation.y 來讓他左右反轉。在 FixedUpdate() 的 inputDirection 被定義後填入以下程式碼:
// 檢查玩家所按下的方向,並改變角色面對的方向
if (inputDirection > 0.01f)
this.transform.rotation = Quaternion.Euler(0, 0, 0);
else if (inputDirection < -0.01f)
this.transform.rotation = Quaternion.Euler(0, 180, 0);
接著我們可以處理跳躍的部份。跳躍功能我們需要為腳本編寫兩個部份,第一個是判定人物正在和地面接觸,第二個是為人物施加上升的力量。要讓人物能夠進行觸地的判定,我們需要一個遊戲中的位置傳回到腳本中,所以我們要建立一個在人物之下的空遊戲物件,並設定位置在人物的腳下。
然後我們可以在腳本中新增一個遊戲物件的全域變數,並用 SerializeField 去讓我們可以把剛剛建立的遊戲物件拉到腳本中。
[SerializeField] private GameObject groundCheckPoint;
然後我們可以利用 Physic2D 的 OverlapBox 功能去檢查該點有沒有觸碰到碰撞箱,而由於我們人物自身也有碰撞箱,我們要設定檢查的圖層,並把先前製作的場景轉換到該圖層。各位可以先利用 Debug.Log() 確認自己的遊戲物件等設定到這步之前有沒有出錯。
// 觸地判定
if (Physics2D.OverlapBox(groundCheckPoint.transform.position, new Vector2(0.1f, 0.1f), 0, LayerMask.GetMask("Ground")))
Debug.Log("JUMP");
這裹的圖層和渲染順序無關,可放心設定。
然後我們只要設定跳躍的力度數值以及 AddForce(),角色就會在每次碰到地面時進行跳躍:
[SerializeField] private float jumpForce = 10f;
if (Physics2D.OverlapBox(groundCheckPoint.transform.position, new Vector2(0.1f, 0.1f), 0, LayerMask.GetMask("Ground")))
{
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
}
然而現在出現了一個問題,角色每次跳躍的高度都有可能出現不同,這是因為角色被施力的次數可能多於1次,以及本身在下墜的力量和跳躍的力量互相抵銷。由於第一次觸發跳躍的施力後,下一幀的角色未必會上升至離開判定範圍的高度而被系統再次觸發施力。雖然縮小判定範圍也有可能可以解決這問題,但為每次施力後增加冷卻時間會讓判定變的更穩定。而力量被抵銷,則可以在跳躍前重置玩家的上下速率。
先建立一個全域變數去計算上一次起跳的時間:
private int lastJumpTime = 1000;
然後為跳躍的判定增加一個時間限制,並在跳躍施力前重置上下速率,以及在跳躍施力後重置跳躍時間:
if (Physics2D.OverlapBox(groundCheckPoint.transform.position, new Vector2(0.1f, 0.1f), 0, LayerMask.GetMask("Ground")) && lastJumpTime > 30)
{
rb.velocity = new Vector2(rb.velocity.x, 0);
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
lastJumpTime = 0;
}
最後在 FixedUpdate() 的最後為每一次更新都增加最後跳躍時間:
lastJumpTime++;